package com.aquarium.module;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Timer;
import java.util.TimerTask;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;

import com.aquarium.R;
import com.aquarium.alias.AliasManager;
import com.aquarium.bt.BTManager;
import com.aquarium.config.DosingPumpData;
import com.aquarium.config.ModuleData;
import com.aquarium.config.ProteinSkimmerData;
import com.aquarium.config.UVLightData;
import com.aquarium.config.WaterMotorData;
import com.aquarium.config.WaveMotorData;
import com.aquarium.data.ModuleSettingDataBase;

public class ModuleControlService extends Service {

	public final static String ACTION_UPDATE_WATER_MOTOR_DATA = "ACTION_UPDATE_WATER_MOTOR_DATA";
	public final static String ACTION_UPDATE_PROTEIN_SKIMMER_DATA = "ACTION_UPDATE_PROTEIN_SKIMMER_DATA";
	public final static String ACTION_UPDATE_UV_LIGHT_DATA = "ACTION_UPDATE_UV_LIGHT_DATA";
	public final static String ACTION_UPDATE_DOSING_PUMP_DATA = "ACTION_UPDATE_DOSING_PUMP_DATA";
	public final static String ACTION_UPDATE_WAVE_MOTOR_1_DATA = "ACTION_UPDATE_WAVE_MOTOR_1_DATA";
	public final static String ACTION_UPDATE_WAVE_MOTOR_2_DATA = "ACTION_UPDATE_WAVE_MOTOR_2_DATA";

	public final static int HANDLE_PAUSE_RESTART_TIMER = 1;

	private ArrayList<WaterMotorData> mWaterMotorDataList;
	private ArrayList<ProteinSkimmerData> mProteinSkimmerDataList;
	private ArrayList<UVLightData> mUVLightDataList;
	private ArrayList<DosingPumpData> mDosingPumpDataList;
	private ArrayList<WaveMotorData> mWaveMotorDataList1;
	private ArrayList<WaveMotorData> mWaveMotorDataList2;

	private ModuleSettingDataBase mModuleSettingDataBase;
	private Calendar mCalendar;
	private AliasManager mAliasManager;
	private ModuleController mModuleController;

	private TimepieceTimerTask mTimepieceTimerTask;
	private Timer mTimepieceTimer;
	private Timer mProteinSkimmerTimer;
	private Timer mUVLightTimer;
	private DataUpdateBroadcastReceiver mReceiver;

	private boolean mNeedRest;

	private Handler mHandler = new Handler() {
		public void handleMessage(Message msg) {
			switch (msg.what) {
			case HANDLE_PAUSE_RESTART_TIMER:
				if (mTimepieceTimer != null) {
					mTimepieceTimer.cancel();
				}
				mTimepieceTimer = new Timer();
				mTimepieceTimerTask = new TimepieceTimerTask();
				mTimepieceTimer.schedule(mTimepieceTimerTask, 60 * 1000, 1000);
				mNeedRest = false;
				break;
			default:
				break;
			}
		};
	};

	class DataUpdateBroadcastReceiver extends BroadcastReceiver {

		@Override
		public void onReceive(Context context, Intent intent) {
			String action = intent.getAction();
			if (ACTION_UPDATE_WATER_MOTOR_DATA.equals(action)) {
				updateWaterMotorDataList();
			} else if (ACTION_UPDATE_PROTEIN_SKIMMER_DATA.equals(action)) {
				updateProteinSkimmerDataList();
			} else if (ACTION_UPDATE_UV_LIGHT_DATA.equals(action)) {
				updateUVLightDataList();
			} else if (ACTION_UPDATE_DOSING_PUMP_DATA.equals(action)) {
				updateDosingPumpDataList();
			} else if (ACTION_UPDATE_WAVE_MOTOR_1_DATA.equals(action)) {
				updateWaveMotor1DataList();
			} else if (ACTION_UPDATE_WAVE_MOTOR_2_DATA.equals(action)) {
				updateWaveMotor2DataList();
			}
		}

	}

	@Override
	public void onCreate() {
		super.onCreate();
		mModuleSettingDataBase = ModuleSettingDataBase.getInstance(this);
		mAliasManager = AliasManager.getInstance(this);
		mModuleController = ModuleController.getInstance(this);
		mCalendar = Calendar.getInstance();
		mTimepieceTimerTask = new TimepieceTimerTask();
		mReceiver = new DataUpdateBroadcastReceiver();
		registerBroadcastReceiver();
		initialDataList();
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		if (mTimepieceTimer != null) {
			mTimepieceTimer.cancel();
		}
		mTimepieceTimer = new Timer();
		mTimepieceTimer.schedule(mTimepieceTimerTask, 0, 1000);
		return super.onStartCommand(intent, flags, startId);
	}

	@Override
	public IBinder onBind(Intent arg0) {
		// TODO Auto-generated method stub
		if (mTimepieceTimer != null) {
			mTimepieceTimer.cancel();
		}
		return null;
	}

	@Override
	public void onDestroy() {
		// TODO Auto-generated method stub
		unregisterReceiver(mReceiver);
		if (mTimepieceTimer != null) {
			mTimepieceTimer.cancel();
		}
		if (mProteinSkimmerTimer != null) {
			mProteinSkimmerTimer.cancel();
		}
		if (mUVLightTimer != null) {
			mUVLightTimer.cancel();
		}
		super.onDestroy();
	}

	public class TimepieceTimerTask extends TimerTask {
		@Override
		public void run() {

			mCalendar = Calendar.getInstance();
			int week = mCalendar.get(Calendar.DAY_OF_WEEK);
			boolean isAM = mCalendar.get(Calendar.AM_PM) == Calendar.AM ? true
					: false;
			int hour = mCalendar.get(Calendar.HOUR);
			int minute = mCalendar.get(Calendar.MINUTE);
			controlWaterMotor(week, hour, minute, isAM);
			controlProteinSkimmer(week, hour, minute, isAM);
			controlUVLight(week, hour, minute, isAM);
			controlDosingPump(week, hour, minute, isAM);
			controlWaveMotor(1, week, hour, minute, isAM);
			controlWaveMotor(2, week, hour, minute, isAM);

			// if (mNeedRest) {
			// mHandler.sendEmptyMessage(HANDLE_PAUSE_RESTART_TIMER);
			// }
		}
	}

	private void controlWaterMotor(int week, int hour, int minute, boolean isAM) {
		final String moduleName = getResources()
				.getString(R.string.water_motor);
		for (WaterMotorData data : mWaterMotorDataList) {
			if (!isTimeUp(data, week, hour, minute, isAM)) {
				continue;
			}
			mModuleController.sendModuleOnOffCommand(moduleName, data.isOn,
					false, null);
			mNeedRest = true;
		}

	}

	private void controlProteinSkimmer(int week, int hour, int minute,
			boolean isAM) {
		final String moduleName = getResources().getString(
				R.string.protein_skimmer);
		for (ProteinSkimmerData data : mProteinSkimmerDataList) {
			if (!isTimeUp(data, week, hour, minute, isAM)) {
				continue;
			}
			int duration = data.duration;
			mModuleController.sendModuleOnOffCommand(moduleName, true, false,
					null);
			mNeedRest = true;
			if (mProteinSkimmerTimer != null) {
				mProteinSkimmerTimer.cancel();
			}
			mProteinSkimmerTimer = new Timer();
			mProteinSkimmerTimer.schedule(new TimerTask() {

				@Override
				public void run() {
					mModuleController.sendModuleOnOffCommand(moduleName, false,
							false, null);
				}
			}, duration * 60 * 1000);
		}
	}

	private void controlUVLight(int week, int hour, int minute, boolean isAM) {
		final String moduleName = getResources().getString(R.string.uv_light);
		for (UVLightData data : mUVLightDataList) {
			if (!isTimeUp(data, week, hour, minute, isAM)) {
				continue;
			}
			mModuleController.sendModuleOnOffCommand(moduleName, true, false,
					null);
			mNeedRest = true;
			if (mUVLightTimer != null) {
				mUVLightTimer.cancel();
			}
			mUVLightTimer = new Timer();
			mUVLightTimer.schedule(new TimerTask() {

				@Override
				public void run() {
					mModuleController.sendModuleOnOffCommand(moduleName, false,
							false, null);
				}
			}, 2 * 60 * 60 * 1000);
		}
	}

	private void controlDosingPump(int week, int hour, int minute, boolean isAM) {
		final String moduleName = getResources()
				.getString(R.string.dosing_pump);
		for (DosingPumpData data : mDosingPumpDataList) {
			if (!isTimeUp(data, week, hour, minute, isAM)) {
				continue;
			}
			mNeedRest = true;
			if (data.isPump1On) {
				mModuleController.sendDosingPumpCommand(moduleName, 1,
						data.pump1Dosing);
			}
			if (data.isPump2On) {
				mModuleController.sendDosingPumpCommand(moduleName, 2,
						data.pump2Dosing);
			}
			if (data.isPump3On) {
				mModuleController.sendDosingPumpCommand(moduleName, 3,
						data.pump3Dosing);
			}
			if (data.isPump4On) {
				mModuleController.sendDosingPumpCommand(moduleName, 4,
						data.pump4Dosing);
			}
		}
	}

	private void controlWaveMotor(int motorId, int week, int hour, int minute,
			boolean isAM) {
		String moduleName = "";
		switch (motorId) {
		case 1:
			moduleName = getResources().getString(R.string.wave_motor1);
			for (WaveMotorData data : mWaveMotorDataList1) {
				if (!isTimeUp(data, week, hour, minute, isAM)) {
					continue;
				}
				mModuleController.sendWaveMotorCommand(moduleName, data.index,
						data.waveMode, false, null);
				mNeedRest = true;
			}
			break;
		case 2:
			moduleName = getResources().getString(R.string.wave_motor2);
			for (WaveMotorData data : mWaveMotorDataList2) {
				if (!isTimeUp(data, week, hour, minute, isAM)) {
					continue;
				}
				mModuleController.sendWaveMotorCommand(moduleName, data.index,
						data.waveMode, false, null);
				mNeedRest = true;
			}
			break;
		default:
			break;
		}
	}

	private boolean isTimeUp(ModuleData data, int week, int hour, int minute,
			boolean isAm) {

		if (data.isAM != isAm) {
			return false;
		}
		if (data.hour != hour) {
			return false;
		}
		if (data.minute != minute) {
			return false;
		}
		if (data.isMon && week == Calendar.MONDAY) {
			return true;
		}
		if (data.isTues && week == Calendar.TUESDAY) {
			return true;
		}
		if (data.isWed && week == Calendar.WEDNESDAY) {
			return true;
		}
		if (data.isThur && week == Calendar.THURSDAY) {
			return true;
		}
		if (data.isFri && week == Calendar.FRIDAY) {
			return true;
		}
		if (data.isSat && week == Calendar.SATURDAY) {
			return true;
		}
		if (data.isSun && week == Calendar.SUNDAY) {
			return true;
		}
		return false;
	}

	private void updateDataList() {
		updateWaterMotorDataList();
		updateProteinSkimmerDataList();
		updateUVLightDataList();
		updateDosingPumpDataList();
		updateWaveMotor1DataList();
		updateWaveMotor2DataList();
	}

	private void updateWaterMotorDataList() {
		mWaterMotorDataList = mModuleSettingDataBase.queryWaterMotorDataList();
	}

	private void updateProteinSkimmerDataList() {
		mProteinSkimmerDataList = mModuleSettingDataBase
				.queryProteinSkimmerDataList();
	}

	private void updateUVLightDataList() {
		mUVLightDataList = mModuleSettingDataBase.queryUVLightDataList();
	}

	private void updateDosingPumpDataList() {
		mDosingPumpDataList = mModuleSettingDataBase.queryDosingPumpDataList();
	}

	private void updateWaveMotor1DataList() {
		mWaveMotorDataList1 = mModuleSettingDataBase.queryWaveMotorDataList(1);
	}

	private void updateWaveMotor2DataList() {
		mWaveMotorDataList2 = mModuleSettingDataBase.queryWaveMotorDataList(2);
	}

	private void registerBroadcastReceiver() {
		IntentFilter filter = new IntentFilter(ACTION_UPDATE_WATER_MOTOR_DATA);
		registerReceiver(mReceiver, filter);
		filter = new IntentFilter(ACTION_UPDATE_PROTEIN_SKIMMER_DATA);
		registerReceiver(mReceiver, filter);
		filter = new IntentFilter(ACTION_UPDATE_UV_LIGHT_DATA);
		registerReceiver(mReceiver, filter);
		filter = new IntentFilter(ACTION_UPDATE_DOSING_PUMP_DATA);
		registerReceiver(mReceiver, filter);
		filter = new IntentFilter(ACTION_UPDATE_WAVE_MOTOR_1_DATA);
		registerReceiver(mReceiver, filter);
		filter = new IntentFilter(ACTION_UPDATE_WAVE_MOTOR_2_DATA);
		registerReceiver(mReceiver, filter);
	}

	private void initialDataList() {
		updateDataList();
	}

}
